package it.tukano.io;

import it.tukano.io.FileExt.InputStreamCall;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZipWriter {
    
    public static void main(String[] args) {
        ZipWriter out = new ZipWriter(new FileExt("test.jar"));
        FileExt in = new FileExt("c:\\users\\pgi\\documents\\reportlayout.jar");
        try {
            out.acquireZip(in);
        } catch (IOException ex) {
            Logger.getLogger(ZipWriter.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                out.finishAndClose();
            } catch (IOException ex) {
                Logger.getLogger(ZipWriter.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    
    private final FileExt file;
    private ZipOutputStream stream;
    private final Set<String> entries = new HashSet<String>();

    /**
     * Instance initializer
     */
    public ZipWriter(FileExt file) {
        this.file = file;
    }
    
    public void acquireZip(FileExt file) throws IOException {
        ZipReader reader = new ZipReader(file);
        for (ZipEntry zipEntry : reader.listEntries()) {
            String name = zipEntry.getName();
            if(entries.contains(name)) continue;
            
            if(zipEntry.isDirectory()) {
                createDirectory(name);
            } else {
                InputStream in = reader.openEntry(zipEntry);
                acquireStream(zipEntry.getName(), in);
            }
        }
    }
    
    public void acquireFile(FileExt file) throws IOException {
        final String name = file.getFile().getName();
        if(entries.contains(name)) return;
        
        entries.add(name);
        final ZipOutputStream out = getStream();
        ZipEntry e = new ZipEntry(name);
        out.putNextEntry(e);
        file.withInputStream(new InputStreamCall<Void>() {

            public Void call(InputStream in) throws Throwable {
                doTransfer(in, out);
                return null;
            }
        });
    }
    
    public void createDirectory(String name) throws IOException {
        if(!name.endsWith("/")) name = name + "/";
        if(entries.contains(name)) return;
        entries.add(name);
        
        getStream().putNextEntry(new ZipEntry(name));
    }
    
    public void finishAndClose() throws IOException {
        if(stream != null) {
            try {
                stream.finish();
            } finally {
                stream.close();
            }
        }
    }

    private void doTransfer(InputStream in, ZipOutputStream out) throws IOException {
        byte[] buffer = new byte[1024];
        int r = in.read(buffer);
        if(r != -1) {
            out.write(buffer, 0, r);
        }
    }

    private ZipOutputStream getStream() throws IOException {
        if(stream == null) {
            stream = new ZipOutputStream(file.getOutputStream(false));
        }
        return stream;
    }

    public void acquireStream(String name, InputStream in) throws IOException {
        if(entries.contains(name)) return;
        
        entries.add(name);
        ZipOutputStream out = getStream();
        out.putNextEntry(new ZipEntry(name));
        doTransfer(in, out);
    }
}
